#!/usr/local/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) The PyAMF Project.
# See LICENSE.txt for details.

"""
Example socket server using Twisted.

@see: U{Documentation for this example<http://pyamf.org/tutorials/actionscript/socket.html>}

@since: 0.1
"""


try:
    import twisted
except ImportError:
    print ("This examples requires the Twisted framework. Download it from http://twistedmatrix.com")
    raise SystemExit

#from twisted.internet import epollreactor
#try:
#    epollreactor.install()
#except ImportError:
#    print ("epoll reactor Install failure")
#    raise SystemExit

from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor

import json

import kernel.base.data as user_data
import kernel.base.function as func
from controller.module_treat import distribute
from kernel.base.advanced import mongo
from config import conf

reactor.suggestThreadPoolSize(60)

distribute=distribute()
mongo_class=mongo()
#设置存储
user_data.setstorage(mongo_class)

class TimerProtocol(Protocol):
#    interval = 1.0  # 客户端链接到server后，server往客户端发送时间的间隔  
    timeout_deferred=False
    timeout = 300       #客户端链接到server后多少时间不操作就断开链接的timeout
    phptimeout=86400    #php的socket断开时间
    

    def __init__(self):
        self.started = False
#        print("初始化完成")

    def connectionLost(self, reason):
        Protocol.connectionLost(self, reason)
        #客户端没断开一个链接，总连接数-1
        self.factory.number_of_connections -= 1
        
        #检测那个用户断开
        tuser_id=user_data.get_userid(self.transport)
        #删除用户注册数据
        if(tuser_id):
            user_data.storage().findone("user_info",{"online":0},{"id":tuser_id})
        user_data.del_user_fp(self.transport)

    def connectionMade(self):
        #如果服务器连接数超过最大连接数，拒绝新链接建立 
        if self.factory.number_of_connections >= self.factory.max_connections:
            func.sendsocet(self.transport, 'Too many connections, try again later')
            self.transport.loseConnection()
            return
        #总连接数+1  
        user_id=func.regid()
        user_data.user_reg(user_id, self.transport)
        
        jsondata=user_data.agreement("api.login", "init", {"res":True,"msg":{"pulse_time":TimerProtocol.timeout-30,"peer":conf.get("PREE")}})
        func.sendsocet(self.transport, jsondata)
        self.factory.number_of_connections += 1
        self.timeout_deferred = reactor.callLater(TimerProtocol.timeout, self.transport.loseConnection)

    def dataReceived(self, data):
        #去除server收到client数据两端的空格 
        data = data.strip().decode()
        print(data,"=================")
        datalist=data.split("###")
        for key in datalist:
            strdata=key
            if(len(strdata)<3):
                continue
                
            if strdata =="pulse":#心跳
                #每次执行完客户端请求后重置timeout，重新开始计算无操作时间。
                self.timemax(TimerProtocol.timeout,self.transport)
            else:
                try:
                    self.datac(strdata)
                except ImportError:
                    raise SystemExit
            
    #这个函数是命根子啊，相当重要
    def datac(self,data):
        data_json=func.jsond(data)
        if(data_json==False):
            return False

        if(func.is_arr(data_json, "type")==False or func.is_arr(data_json, "module")==False or func.is_arr(data_json, "fun")==False):
            return False
        
        if(func.is_arr(data_json, "parameter")==False):
            data["parameter"]=[]
        
        socket_type=data_json["type"]
        if(socket_type=="return"):#后端已经成功返回数据
            print("后端已经成功返回数据")
            self.returnc(data_json)
        else:#python程序处理 通常socket_type==python
            print("python模块为您服务")
            self.pythonc(data_json)
            
    #python数据处理
    def pythonc(self,data_json): 
        user_id=user_data.get_userid(self.transport)
        if(data_json["module"]!="api.movie_list" and user_data.get_user(user_id, "login")==0):#其他模块,没登录的,一律不允许使用
            jsondata=user_data.agreement("api.login", "notlogin", {"res":False,"msg":"您没有登录,无法使用其他模块"})
            func.sendsocet(self.transport, jsondata)
            return False
        
        print("准备call")
        tmpdata=distribute.call(user_id,data_json)
        
        if(tmpdata):
            data_json["return"]=tmpdata
            data_json["sys"]=False
            print(json.dumps(data_json))
            func.sendsocet(self.transport,data_json)
            
        #每次执行完客户端请求后重置timeout，重新开始计算无操作时间。
        self.timemax(TimerProtocol.timeout,self.transport)
        print("指令执行完成==over==")
        
    #返回数据处理配合AMF用的
    def returnc(self,data_json):
        if "return" in data_json==False:
            return False
        
        #如果是数组呢？？？
        if ("send_user_id" in data_json["return"]):
            tmpuser_id=data_json["return"]["send_user_id"]
        else:
            tmpuser_id=[data_json["user_id"]]
        
        for uid in tmpuser_id:
            fp=user_data.get_fp(uid)
            if(fp):
                data_json["sys"]=False
                #向前端返回数据
                func.sendsocet(fp,data_json)
                #每次执行完客户端请求后重置timeout，重新开始计算无操作时间。
                self.timemax(TimerProtocol.timeout,fp)
            else:
                continue
    
    #过期时间调整
    def timemax(self,times,fp):
        #每次执行完客户端请求后重置timeout，重新开始计算无操作时间。
        if self.timeout_deferred:
            self.timeout_deferred.cancel()
            self.timeout_deferred = reactor.callLater(times,fp.loseConnection)
            
class TimerFactory(Factory):
    protocol = TimerProtocol
    #最大链接数
    max_connections = 3000

    def __init__(self):
        self.number_of_connections = 0


class SocketPolicyProtocol(Protocol):
    """
    Serves strict policy file for Flash Player >= 9,0,124.
    @see: U{http://adobe.com/go/strict_policy_files}
    """
    def connectionMade(self):
        self.buffer = ''

    def dataReceived(self, data):
        self.buffer += data
        if self.buffer.startswith('<policy-file-request/>'):
            self.transport.write(self.factory.getPolicyFile(self))
            self.transport.loseConnection()


class SocketPolicyFactory(Factory):
    protocol = SocketPolicyProtocol

    def __init__(self, policy_file):
        """
        @param policy_file: Path to the policy file definition
        """
        self.policy_file = policy_file

    def getPolicyFile(self, protocol):
        return open(self.policy_file, 'rt').read()

class movieconn:
    def conn(self,host,appPort,policyPort,policyFile):
        from optparse import OptionParser
        
        parser = OptionParser()
        parser.add_option("--host", default=host,dest="host", help="host address [default: %default]")
        
        parser.add_option("-a", "--app-port", default=appPort,dest="app_port", help="Application port number [default: %default]")
        
        parser.add_option("-p", "--policy-port", default=policyPort,dest="policy_port", help="Socket policy port number [default: %default]")
        
        parser.add_option("-f", "--policy-file", default=policyFile,dest="policy_file", help="Location of socket policy file [default: %default]")
        
        (opt, args) = parser.parse_args()
    
        print ("Running Socket AMF gateway on %s:%s" % (opt.host, opt.app_port))
        print ("Running Policy file server on %s:%s" % (opt.host, opt.policy_port))
        
        reactor.listenTCP(int(opt.app_port), TimerFactory(), interface=opt.host)
        reactor.listenTCP(int(opt.policy_port), SocketPolicyFactory(opt.policy_file),interface=opt.host)
        reactor.run()
        
    